package org.windowkit.toolkit.print;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.text.MessageFormat;

import javax.print.PrintService;
import javax.print.attribute.Size2DSyntax;
import javax.print.attribute.standard.MediaSize;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.PrinterName;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

import org.ddevil.data.LightweightAttributes;
import org.windowkit.toolkit.widget.PageSelector;
import org.windowkit.toolkit.widget.combo.DataSetComboBox;
import org.windowkit.toolkit.widget.text.TextField;


/**
 *
 * @author Eric Lundin
 */
// TODO BROKED
public class PrintPreviewView {


	/**
	 *
	 */
	private static final String PRINTER_LABEL = "Printer:";

	/**
	 *
	 */
	private static final String PAGE_FORMAT_DISPLAY_MSG = "{0,number,##.##}\" X {1,number,##.##}\"";

	/**
	 * The label for the page format label.
	 */
	private static final String PAGE_FORMAT_LABEL = "Format:";

	/**
	 *
	 */
	private static final String PAGE_FORMAT = "Format";

	/**
	 * Text to display on cancel button.
	 */
	private static final String CANCEL = "Cancel";

	/**
	 * Text to display on print button.
	 */
	private static final String PRINT_LABEL = "Print";

	/**
	 * Padding for each component in the x direction.
	 */
	private static final int PAD_X = 4;

	/**
	 * Padding for each component in the y direction.
	 */
	private static final int PAD_Y = 4;

	/**
	 * Insets for panels.
	 */
	private static final Insets insets = new Insets(2, 2, 2, 2);

	/**
	 * Displays the current page image.
	 */
	protected ImageDisplay imageDisplay;

	/**
	 * Tells the print utility to print the previewed image.
	 */
	protected JButton printButton;

	/**
	 * Cancels the print process.
	 */
	protected JButton cancelButton;

	/**
	 * Allows the user to navigate between pages.
	 */
	protected PageSelector slider;

	/**
	 * Allows the user to preview the print job on different available printers.
	 */
	protected DataSetComboBox availablePrinters;

	/**
	 * Allows the user to change the current page format.
	 */
	protected JButton pageFormatButton;

	/**
	 * Displays the current pageFormat
	 */
	protected TextField pageFormatDisplay;

	protected JLabel pageFormatLabel;

	/**
	 * Displays current status information.
	 */
	protected JLabel statusLabel;

	/**
	 * The status bar to be displayed at the bottom of the screen
	 */
	JToolBar statusBar;

	/**
	 * Label for dropdown box of printers.
	 */
	protected JLabel availablePrintersLabel;

	/**
	 * Label for page index selector.
	 */
	protected JLabel pageIndexLabel;

	/**
	 * Panel to hold the component which will display images.
	 */
	protected JPanel imagePanel;

	/**
	 * Panel to display buttons.
	 */
	protected JPanel buttonPanel;

	/**
	 * Panel to display printer combobox and page selection control.
	 */
	protected JPanel selectionPanel;

	/**
	 * Lets the user know the window is working.
	 */
	protected JProgressBar progressBar;

	/**
	 * Displays and scrolls the current image.
	 */
	protected ImageScroller imageScroller;

	/**
	 * Holds the panels containing the components for this view.
	 */
	protected JPanel mainPanel;

	/**
	 *
	 */
	public PrintPreviewView(/* int numberOfPages */) {
		super();
		layoutComponents();
	}

	/**
	 * Initializes and laysout the controls.
	 */
	private void layoutComponents(/* int numberOfPages */) {
		initializeComponents(/* numberOfPages */);
		setupComponents();
		layoutButtonPanel();
		layoutSelectionPanel();
		layoutStatusBar();
		layoutMainPanel();

		// TODO BROKED
//		setLayout(new BorderLayout());
//		add(mainPanel, BorderLayout.CENTER);
//		add(statusBar, BorderLayout.SOUTH);

	}

	/**
	 * Set any necessary attributes on the components.
	 */
	private void setupComponents() {
		imagePanel.setBorder(new CompoundBorder(new TitledBorder("Preview"),
				new EmptyBorder(2, 2, 2, 2)));
		imagePanel.setLayout(new BorderLayout());
		imagePanel.add(imageScroller, BorderLayout.CENTER);
		pageFormatDisplay.setEditable(false);
		imageScroller.setPreferredSize(new Dimension(468, 648));
	}

	/**
	 * Layout all the panels containing the components.
	 */
	private void layoutMainPanel() {
		mainPanel.setLayout(new BorderLayout());
		mainPanel.add(selectionPanel, BorderLayout.NORTH);
		mainPanel.add(imagePanel, BorderLayout.CENTER);
		mainPanel.add(buttonPanel, BorderLayout.SOUTH);
	}

	/**
	 * Layout the status bar.
	 */
	private void layoutStatusBar() {
		GridBagConstraints gbc = createDefaultConstraints();
		statusBar.setLayout(new GridBagLayout());
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.gridx = 0;
		gbc.gridwidth = 4;
		gbc.weightx = 1;
		gbc.anchor = GridBagConstraints.WEST;
		statusBar.add(statusLabel, gbc);
		gbc.weightx = 0;
		gbc.gridx = GridBagConstraints.RELATIVE;
		gbc.gridwidth = 1;
		gbc.anchor = GridBagConstraints.EAST;
		statusBar.add(progressBar, gbc);
	}

	/**
	 * Layout the components above the image.
	 */
	private void layoutSelectionPanel() {
		GridBagConstraints gbc;
		selectionPanel.setLayout(new GridBagLayout());
		gbc = createDefaultConstraints();

		gbc.gridx = 0;
		gbc.fill = GridBagConstraints.NONE;
		gbc.anchor = GridBagConstraints.EAST;
		gbc.weightx = 0;
		selectionPanel.add(availablePrintersLabel, gbc);
		gbc.anchor = GridBagConstraints.WEST;
		gbc.fill = GridBagConstraints.HORIZONTAL;

		gbc.weightx = 1;
		gbc.gridx = GridBagConstraints.RELATIVE;
		selectionPanel.add(availablePrinters, gbc);

		gbc.weightx = 0;
		gbc.fill = GridBagConstraints.NONE;
		selectionPanel.add(slider, gbc);
		gbc.gridx = 0;
		gbc.gridy = 1;
		gbc.anchor = GridBagConstraints.EAST;
		selectionPanel.add(pageFormatLabel, gbc);
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.anchor = GridBagConstraints.WEST;
		gbc.gridx = GridBagConstraints.RELATIVE;
		gbc.weightx = 1;
		selectionPanel.add(pageFormatDisplay, gbc);
		gbc.weightx = 0;
		selectionPanel.add(pageFormatButton, gbc);
	}

	/**
	 * Layout the buttons on this view.
	 */
	private void layoutButtonPanel() {
		buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
		buttonPanel.add(Box.createHorizontalGlue());
		buttonPanel.add(cancelButton);
		buttonPanel.add(Box.createHorizontalStrut(PAD_X));
		buttonPanel.add(printButton);
		buttonPanel.add(Box.createHorizontalStrut(PAD_X / 4));
		buttonPanel.setBorder(new EmptyBorder(insets));
	}

	/**
	 * Initialize all components needed for this layout.
	 *
	 * @param numberOfPages
	 *            The number of pages in the print job.
	 */
	private void initializeComponents(/* int numberOfPages */) {
		mainPanel = new JPanel();
		printButton = new JButton(PRINT_LABEL);
		cancelButton = new JButton(CANCEL);
		pageFormatButton = new JButton(PAGE_FORMAT);
		slider = new PageSelector(1, 1/* numberOfPages */);
		statusLabel = new JLabel();
		availablePrinters = new DataSetComboBox("printerName", "printer");
		mainPanel = new JPanel();
		availablePrintersLabel = new JLabel(PRINTER_LABEL);
		buttonPanel = new JPanel();
		selectionPanel = new JPanel();
		imagePanel = new JPanel();
		progressBar = new JProgressBar();
		pageFormatButton.setEnabled(false);
		pageFormatDisplay = new TextField(10);
		statusBar = new JToolBar();
		statusBar.setFloatable(false);
		imageScroller = new ImageScroller();
		pageFormatLabel = new JLabel(PAGE_FORMAT_LABEL);
	}

	/**
	 * Creates default constraints out of convienience.
	 *
	 * @return Constrants with the class constant xPadding, yPadding, and insets
	 *         defined.
	 */
	private GridBagConstraints createDefaultConstraints() {
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.ipadx = PAD_X;
		gbc.ipady = PAD_Y;
		gbc.insets = insets;
		return gbc;
	}

	/**
	 * Load the printer names and their corresponding services to combobox.
	 *
	 * @param services
	 *            The available print services the user may want to preview the
	 *            print job with.
	 */
	public void populateCombobox(final PrintService[] services) {
		String currentName;
		for (PrintService current : services) {
			currentName = current.getAttribute(PrinterName.class).getValue();
//			availablePrinters.addItem(currentName, new Object[] { current });
			availablePrinters.addItem(new LightweightAttributes(
					new String[]{"printerName", "printer"},
					new Object[] {currentName, current}));
		}
	}



	/**
	 * Set the selected option.
	 *
	 * @param printer
	 *            The printer to select.
	 */
	public void setSelectedPrinter(final PrintService printer) {
		String name = printer.getAttribute(PrinterName.class).getValue();
		availablePrinters.setSelectedOption(name);
	}

	/**
	 * Initialize the page selector.
	 *
	 * @param min
	 *            The minimum page number.
	 * @param max
	 *            The maximum page number.
	 * @param value
	 *            The initial value.
	 */
	public void initializePageSelector(final int min, final int max, final int value) {
		slider.setMinimum(min);
		slider.setMaximum(max);
		slider.setValue(value);
	}

	/**
	 * Get the currently selected PrintService from the combobox.
	 *
	 * @return The currently selected printer's corresponding PrintService.
	 */
	public PrintService getSelectedPrintService() {
		return (PrintService) availablePrinters.getSelectedData().getValue("printer");
	}

	public void setProgressBarIndeterminate(final boolean indeterminate) {
		progressBar.setIndeterminate(indeterminate);
	}

	public void setStatusBarActive(final boolean active) {
		progressBar.setIndeterminate(active);
	}

	public JScrollPane getImageScrollPane() {
		return imageScroller;
	}

	public void setDisplayedImage(final BufferedImage image) {
		imageScroller.setImage(image);
	}

	public ImageScroller getImageDisplay() {
		return imageScroller;
	}

//	public int getSliderValue() {
//		return slider.getValue();
//	}

	public PageSelector getPageSelector() {
		return slider;
	}

	public void setStatusBarText(final String text) {
		statusLabel.setText(text);
	}

	public DataSetComboBox getAvailablePrintersCombo() {
		return availablePrinters;
	}

	public JButton getCancelButton() {
		return cancelButton;
	}

	//XXX BROKED
//	@Override
//	public void setListener(Control listener) {
//		if (listener instanceof ChangeListener) {
//			slider.addChangeListener((ChangeListener) listener);
//		}
//		if (listener instanceof ActionListener) {
//			availablePrinters.addActionListener((ActionListener) listener);
//			cancelButton.addActionListener((ActionListener) listener);
//			printButton.addActionListener((ActionListener) listener);
//			pageFormatButton.addActionListener((ActionListener) listener);
//		}
//	}

	/**
	 * Set whether the Format button is enabled.
	 *
	 * @param enabled
	 *            True if enabled false otherwise.
	 */
	public void setFormatButtonEnabled(final boolean enabled) {
		pageFormatButton.setEnabled(enabled);
	}

	/**
	 * Sets the displayed page format.
	 *
	 * @param format
	 *            The format currently being used.
	 */
	public void setFormatDisplay(final PageFormat format) {
		boolean landscape = false;
		double swap;
		double width = (format.getWidth() / 72.0d);
		double height = (format.getHeight() / 72.0d);
		String displayString;
		if (format.getOrientation() == PageFormat.LANDSCAPE) {
			landscape = true;
			swap = width;
			width = height;
			height = swap;
		}
		displayString = buildFormatString(landscape, width, height);
		pageFormatDisplay.setText(displayString);
	}

	/**
	 * Build the page format string to be displayed.
	 *
	 * @param landscape
	 *            True if the pageformat is in landscape mode.
	 * @param width
	 *            The width of the page.
	 * @param height
	 *            The height of the page.
	 * @return The string to display describing the page format.
	 */
	private String buildFormatString(final boolean landscape, final double width,
			final double height) {
		MediaNameDecoder decoder;
		String displayString;
		String mediaName = new String("");
		MediaSizeName name = MediaSize.findMedia((float) width, (float) height,
				Size2DSyntax.INCH);
		if (name != null) {
			decoder = new MediaNameDecoder(name);
			mediaName = decoder.decodeMediaName();
		}

		displayString = mediaName + " "
				+ MessageFormat.format(PAGE_FORMAT_DISPLAY_MSG, width, height)
				+ " " + (landscape ? "Landscape" : "Portrait");
		return displayString.trim();
	}

	/**
	 * Displays the images rendered from the print job.
	 *
	 * @author Eric Lundin
	 */
	public class ImageDisplay extends JPanel {
		/**
		 *
		 */
		private static final long serialVersionUID = -5517707768806905725L;
		private BufferedImage currentImage;

		public ImageDisplay() {
		}

		/**
		 * Set the currently displayed image.
		 *
		 * @param image
		 *            The image to display.
		 */
		public void setImage(final BufferedImage image) {
			currentImage = image;
			setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
			// XXX broked
//			PrintPreviewView.this.repaint();
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see java.awt.Component#paint(java.awt.Graphics)
		 */@Override
		public void paint(final Graphics g) {
			super.paint(g);
			if (isShowing()) {
				Graphics2D g2 = (Graphics2D) g;
				g2.drawImage(currentImage, null, 0, 0);
			}
		}
	}

	/**
	 * Scrollpane wrapping a panel which will display the image.
	 *
	 * @author Eric Lundin
	 */
	public class ImageScroller extends JScrollPane {
		/**
		 *
		 */
		private static final long serialVersionUID = -108280233675455101L;
		/**
		 * The component which will display the image.
		 */
		ImageDisplay display;

		public ImageScroller() {
			super();
			display = new ImageDisplay();
			setViewportView(display);

			setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
			setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		}

		/**
		 * Sets the image to be displayed.
		 *
		 * @param image
		 *            The image to display.
		 */
		public void setImage(final BufferedImage image) {
			display.setImage(image);
			getViewport().setViewSize(
					new Dimension(image.getWidth(), image.getHeight()));
		}
	}

}
